package whf.framework.security.acegiimp;

import java.util.Iterator;

import org.acegisecurity.ConfigAttributeDefinition;
import org.acegisecurity.ConfigAttributeEditor;
import org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionMap;
import org.acegisecurity.intercept.web.FilterInvocationDefinitionSource;
import org.acegisecurity.intercept.web.PathBasedFilterInvocationDefinitionMap;
import org.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap;
import org.springframework.beans.factory.InitializingBean;

import whf.framework.log.Log;
import whf.framework.log.LogFactory;

/**
 * 使ACEGI可以存取数据库中定义的资源
 * 
 * @author wanghaifeng
 * @create Nov 29, 2006 4:45:00 PM
 * 
 */
public class RdbmsBasedFilterInvocationDefinitionSource extends
		AbstractFilterInvocationDefinitionSource implements
		ConfigableFilterInvocationDefinition, InitializingBean {

	// ~ Static fields/initializers
	// =============================================

	private static final Log logger = LogFactory.getLog(RdbmsBasedFilterInvocationDefinitionSource.class);

	// ~ Instance fields
	// ========================================================

	private String resourceExpression = PERL5_KEY;

	private boolean convertUrlToLowercaseBeforeComparison = false;

	private ResourceMappingProvider resourceMappingProvider;

	// ~ Methods
	// ================================================================

	public void setResourceMappingProvider(ResourceMappingProvider resourceMappingProvider){
		this.resourceMappingProvider = resourceMappingProvider;
	}
	
	/**
	 * 
	 * @see org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource#lookupAttributes(java.lang.String)
	 */
	public ConfigAttributeDefinition lookupAttributes(String url) {
		FilterInvocationDefinitionSource actualSource = populateFilterInvocationDefinitionSource();

		if (RegExpBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {
			return ((RegExpBasedFilterInvocationDefinitionMap) actualSource).lookupAttributes(url);
		} else if (PathBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {
			return ((PathBasedFilterInvocationDefinitionMap) actualSource).lookupAttributes(url);
		}

		throw new IllegalStateException("wrong type of " + actualSource + ", it should be "
				+ RegExpBasedFilterInvocationDefinitionMap.class + " or " + PathBasedFilterInvocationDefinitionMap.class);
	}

	/**
	 * 
	 * @see org.acegisecurity.intercept.ObjectDefinitionSource#getConfigAttributeDefinitions()
	 */
	public Iterator getConfigAttributeDefinitions() {
		FilterInvocationDefinitionSource actualSource = populateFilterInvocationDefinitionSource();

		if (RegExpBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {
			return ((RegExpBasedFilterInvocationDefinitionMap) actualSource).getConfigAttributeDefinitions();
		} else if (PathBasedFilterInvocationDefinitionMap.class.isInstance(actualSource)) {
			return ((PathBasedFilterInvocationDefinitionMap) actualSource).getConfigAttributeDefinitions();
		}

		throw new IllegalStateException("wrong type of " + actualSource + ", it should be "
				+ RegExpBasedFilterInvocationDefinitionMap.class + " or " + PathBasedFilterInvocationDefinitionMap.class);
	}

	private FilterInvocationDefinitionSource populateFilterInvocationDefinitionSource() {
		FilterInvocationDefinitionMap definitionSource = null;

		if (PERL5_KEY.equals(getResourceExpression())) {
			definitionSource = new RegExpBasedFilterInvocationDefinitionMap();
		} else if (ANT_PATH_KEY.equals(getResourceExpression())) {
			definitionSource = new PathBasedFilterInvocationDefinitionMap();
		} else {
			throw new IllegalArgumentException("wrong resourceExpression value");
		}

		definitionSource.setConvertUrlToLowercaseBeforeComparison(isConvertUrlToLowercaseBeforeComparison());

		ResourceMapping[] mappings = this.resourceMappingProvider.getResourceMappings();
		if (mappings == null || mappings.length == 0) {
			return (FilterInvocationDefinitionSource) definitionSource;
		}

		for (int i = 0; i < mappings.length; i++) {
			ResourceMapping mapping = mappings[i];
			String[] recipents = mapping.getRecipients();
			
			if (recipents == null || recipents.length == 0) {
				if (logger.isErrorEnabled()) {
					logger.error("Notice, the resource : "+ mapping.getResourcePath()+ " hasn't no recipents, it will access by any one ! ");
				}
				continue;
			}

			StringBuffer valueBuffer = new StringBuffer();
			for (int j = 0; j < recipents.length; j++) {
				valueBuffer.append(recipents[j]);
				if (j < recipents.length - 1) {
					valueBuffer.append(STAND_DELIM_CHARACTER);
				}
			}
			String value = valueBuffer.toString();
			addSecureUrl(definitionSource, mapping.getResourcePath(), value);
		}

		return (FilterInvocationDefinitionSource) definitionSource;
	}

	/**
	 * @param source
	 * @param name
	 * @param value
	 * @throws IllegalArgumentException
	 */
	private synchronized void addSecureUrl(
			FilterInvocationDefinitionMap source, String name, String value)
			throws IllegalArgumentException {

		// Convert value to series of security configuration attributes
		ConfigAttributeEditor configAttribEd = new ConfigAttributeEditor();
		configAttribEd.setAsText(value);

		ConfigAttributeDefinition attr = (ConfigAttributeDefinition) configAttribEd.getValue();

		// Register the regular expression and its attribute
		source.addSecureUrl(name, attr);
	}

	/* (non-Javadoc)
	 * @see whf.framework.auth.acegiimp.ConfigableFilterInvocationDefinition#isConvertUrlToLowercaseBeforeComparison()
	 */
	public boolean isConvertUrlToLowercaseBeforeComparison() {
		return this.convertUrlToLowercaseBeforeComparison;
	}

	/* (non-Javadoc)
	 * @see whf.framework.auth.acegiimp.ConfigableFilterInvocationDefinition#setConvertUrlToLowercaseBeforeComparison(boolean)
	 */
	public void setConvertUrlToLowercaseBeforeComparison(boolean convertUrlToLowercaseBeforeComparison) {
		this.convertUrlToLowercaseBeforeComparison = convertUrlToLowercaseBeforeComparison;
	}

	/* (non-Javadoc)
	 * @see whf.framework.auth.acegiimp.ConfigableFilterInvocationDefinition#getResourceExpression()
	 */
	public String getResourceExpression() {
		return this.resourceExpression;
	}

	/* (non-Javadoc)
	 * @see whf.framework.auth.acegiimp.ConfigableFilterInvocationDefinition#setResourceExpression(java.lang.String)
	 */
	public void setResourceExpression(String resourceExpression) {
		this.resourceExpression = resourceExpression;
	}

	/* (non-Javadoc)
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		
	}

}
